﻿using System;
using System.Data;
using MyClever.Lib;

namespace MyClever.DefaultPlugins
{
    public class WordStemmingGermany : MissionPlugin
    {
        [Package(Direction.Input, "Defines all german keywords you like to stem.")]
        enum Keywords
        {
            [Column(typeof(string), "Identifies the unstemmed german keyword.")]
            Keyword
        }

        [Package(Direction.Output, "Defines all german stemmed keywords")]
        enum Output
        {
            [Column(typeof(string), "Identifies the unstemmed german keyword.")]
            Raw,
            [Column(typeof(string), "Contains the stemmed keyword, which is not necessarily part of the german dictionary.")]
            StemmedKeyword
        }

        [Plugin(PluginDevStatus.Production, "'A Fast and Simple Stemming Algorithm for German Words' by Jörg Caumanns (joerg.caumanns@isst.fhg.de)")]
        public WordStemmingGermany()
        {
        }

        public override void Initialize()
        {
            //This is the first Function called by the host...
            //Put anything needed to start with here first
        }

        public override void Dispose()
        {
            //Put any cleanup code in here for when the program is stopped
        }


        // ".
        protected override void Work()
        {
            DataTableReader keywordsPackage = this.GetDataReader(typeof(Keywords));
            while (keywordsPackage.Read())
            {
                if (String.Empty != keywordsPackage[Keywords.Keyword.ToString()].ToString())
                {
                    this.AddNewLoggingMessage(typeof(Keywords), String.Format("keyword stemming for: {0}", keywordsPackage[Keywords.Keyword.ToString()].ToString()));

                    DataRow newRow = this.CreateNewRowFromPackage(typeof(Output));

                    newRow[Output.Raw.ToString()] = keywordsPackage[Keywords.Keyword.ToString()].ToString();

                    string substitute = this.Substitute(keywordsPackage[Keywords.Keyword.ToString()].ToString());

                    string stem = this.Strip(keywordsPackage[Keywords.Keyword.ToString()].ToString(), substitute);

                    newRow[Output.StemmedKeyword.ToString()] = this.Resubstitute(stem);

                    this.AddNewRowToPackage(typeof(Output), newRow);
                }
            }
        }


        /**
        * - Substitute Umlauts with their corresponding vowel: äöü -> aou,
        *   "ß" is substituted by "ss"
        * - Substitute a second char of a pair of equal characters with
        *   an asterisk: ?? -> ?*
        * - Substitute some common character combinations with a token:
        *   sch/ch/ei/ie -> $/§/%/&
        */
        private string Substitute(string keyword)
        {
            keyword = keyword.ToLower();

            // Replace the second char of a pair of the equal characters with an asterisk
            for (int i = 0; i < keyword.Length; i++)
            {
                if (i > 0 && keyword[i] == keyword[i - 1])
                {
                    keyword = keyword.Remove(i, 1);
                    keyword = keyword.Insert(i, "*");
                }
            }

            keyword = keyword.Replace('ä', 'a');
            keyword = keyword.Replace('ö', 'o');
            keyword = keyword.Replace('ü', 'u');

            // Take care that at least one character is left left side from the current one
            char lastCharacter = keyword[keyword.Length - 1];
            string cutKeyword = keyword.Substring(0, keyword.Length - 1);

            cutKeyword = cutKeyword.Replace("ß", "ss");
            cutKeyword = cutKeyword.Replace("sch", "$");
            cutKeyword = cutKeyword.Replace("ch", "§");
            cutKeyword = cutKeyword.Replace("ei", "%");
            cutKeyword = cutKeyword.Replace("ie", "&");
            cutKeyword = cutKeyword.Replace("ig", "#");
            cutKeyword = cutKeyword.Replace("st", "!");

            return keyword = cutKeyword + lastCharacter;
        }

        /**
        * Undoes the changes made by substitute.
        */
        private string Resubstitute(string keyword)
        {
            keyword = keyword.ToLower();

            for (int i = 0; i < keyword.Length; i++)
            {
                if (i > 0 && keyword[i] == '*')
                {
                    keyword = keyword.Remove(i, 1);
                    keyword = keyword.Insert(i, keyword[i - 1].ToString());
                }
            }

            keyword = keyword.Replace("$", "sch");
            keyword = keyword.Replace("§", "ch");
            keyword = keyword.Replace("%", "ei");
            keyword = keyword.Replace("&", "ie");
            keyword = keyword.Replace("#", "ig");
            keyword = keyword.Replace("!", "st");

            return keyword;
        }

        /**
        * suffix stripping (stemming) is reduced
        * to the seven "base" suffixes "e", "s", "n", "t", "em", "er" and * "nd",
        * from which all regular suffixes are build of.
        */
        private string Strip(string rawKeyword, string substitudeKeyword)
        {
            bool doMore = true;

            // if a term is shorter than four characters no further characters are removed.
            while (doMore && substitudeKeyword.Length > 3)
            {
                // if a term is shorter than six characters no 'nd' is removed
                if (rawKeyword.Length > 5 && "nd" == substitudeKeyword.Substring(substitudeKeyword.Length - 2, 2))
                {
                    substitudeKeyword = substitudeKeyword.Remove(substitudeKeyword.Length - 2);
                }
                // if a term is shorter than five characters no 'em' is removed
                else if (rawKeyword.Length > 4 && "em" == substitudeKeyword.Substring(substitudeKeyword.Length - 2, 2))
                {
                    substitudeKeyword = substitudeKeyword.Remove(substitudeKeyword.Length - 2);
                }
                // if a term is shorter than five characters no 'er' is removed
                else if (rawKeyword.Length > 4 && "er" == substitudeKeyword.Substring(substitudeKeyword.Length - 2, 2))
                {
                    substitudeKeyword = substitudeKeyword.Remove(substitudeKeyword.Length - 2);
                }
                else if (substitudeKeyword[substitudeKeyword.Length - 1] == 'e')
                {
                    substitudeKeyword = substitudeKeyword.Remove(substitudeKeyword.Length - 1);
                }
                else if (substitudeKeyword[substitudeKeyword.Length - 1] == 's')
                {
                    substitudeKeyword = substitudeKeyword.Remove(substitudeKeyword.Length - 1);
                }
                else if (substitudeKeyword[substitudeKeyword.Length - 1] == 'n')
                {
                    substitudeKeyword = substitudeKeyword.Remove(substitudeKeyword.Length - 1);
                }
                //// "t" occurs only as suffix of verbs.
                //else if (buffer.charAt(buffer.length() - 1) == 't')
                //{
                //    buffer.deleteCharAt(buffer.length() - 1);
                //}
                else
                {
                    doMore = false;
                }
            }
            return substitudeKeyword;
        }
    }
}
